/**
 * Copyright 2018-2019 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.modulelink.module;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.jianggujin.modulelink.JAction;
import com.jianggujin.modulelink.JModule;
import com.jianggujin.modulelink.JModuleListener;
import com.jianggujin.modulelink.JMultiVersionModuleListener;
import com.jianggujin.modulelink.config.JModuleConfig;
import com.jianggujin.modulelink.exception.JModuleNotFoundException;
import com.jianggujin.modulelink.support.JBeanProvider;
import com.jianggujin.modulelink.support.JDisposable;
import com.jianggujin.modulelink.util.JAssert;
import com.jianggujin.modulelink.util.JLogFactory;
import com.jianggujin.modulelink.util.JLogFactory.JLog;
import com.jianggujin.modulelink.util.JModuleClassLoader;

/**
 * 默认模块
 * 
 * @author jianggujin
 *
 */
public class JDefaultModule implements JModule {

    private static final JLog logger = JLogFactory.getLog(JDefaultModule.class);

    /**
     * 模块的配置信息
     */
    private JModuleConfig moduleConfig;
    /**
     * 模块的类加载器
     */
    private JModuleClassLoader moduleClassLoader;
    /**
     * 默认Action
     */
    private JAction defaultAction;
    /**
     * 模块中的Action
     */
    private Map<String, JAction> actions;
    /**
     * 模块监听器
     */
    private List<JModuleListener> listeners;
    /**
     * Bean提供者服务
     */
    private JBeanProvider beanProvider;
    /**
     * 生命周期状态
     */
    private JLifeState lifeState;

    public JDefaultModule() {
        this.lifeState = JLifeState.CREATED;
    }

    @Override
    public Set<String> getActionNames() {
        return this.actions.keySet();
    }

    @Override
    public Collection<JAction> getActions() {
        return this.actions.values();
    }

    @Override
    public String getDefaultActionName() {
        return getDefaultAction().getActionName();
    }

    @Override
    public String optDefaultActionName() {
        return this.defaultAction == null ? null : this.defaultAction.getActionName();
    }

    @Override
    public JAction getAction(String name) {
        JAction action = optAction(name);
        if (action == null) {
            throw new JModuleNotFoundException("could not found action with name:" + name);
        }
        return action;
    }

    @Override
    public JAction optAction(String name) {
        JAssert.checkNotNull(name, "action name must not be null");
        return this.actions.get(name);
    }

    @Override
    public JAction getDefaultAction() {
        JAction action = optDefaultAction();
        if (action == null) {
            throw new JModuleNotFoundException("could not found default action");
        }
        return action;
    }

    @Override
    public JAction optDefaultAction() {
        return this.defaultAction;
    }

    @Override
    public Object doAction(String actionName, Object in) {
        return doAction(getAction(actionName), in);
    }

    @Override
    public boolean has(String actionName) {
        return actionName != null && this.actions.containsKey(actionName);
    }

    @Override
    public Object doDefaultAction(Object in) {
        return doAction(getDefaultAction(), in);
    }

    /**
     * 执行Action
     * 
     * @param action 需要执行的Action
     * @param in     输入对象
     * @return 执行结果
     */
    private Object doAction(JAction action, Object in) {
        return action.execute(in);
    }

    @Override
    public boolean hasDefaultAction() {
        return this.defaultAction != null;
    }

    @Override
    public synchronized void initialize() throws Exception {
        JAssert.checkState(JLifeState.CREATED == this.lifeState, "module state is not created");
        this.publishLoadedEvent();
        this.lifeState = JLifeState.INITIALIZED;
    }

    @Override
    public synchronized void destroy() throws Exception {
        JAssert.checkState(JLifeState.INITIALIZED == this.lifeState, "module state is not initialized");
        for (Entry<String, JAction> entry : this.actions.entrySet()) {
            if (entry.getValue() instanceof JDisposable) {
                ((JDisposable) entry.getValue()).destroy();
            }
        }
        this.destroyInternal();
        this.publishUnloadedEvent();
        this.lifeState = JLifeState.DESTROYED;
    }

    protected void destroyInternal() throws Exception {
    }

    @Override
    public boolean isInitialized() {
        return JLifeState.INITIALIZED == this.lifeState;
    }

    @Override
    public boolean isDestroyed() {
        return JLifeState.DESTROYED == this.lifeState;
    }

    @Override
    public JModuleConfig getModuleConfig() {
        return moduleConfig;
    }

    @Override
    public ClassLoader getModuleClassLoader() {
        return moduleClassLoader;
    }

    public void setModuleConfig(JModuleConfig moduleConfig) {
        this.moduleConfig = moduleConfig;
    }

    public void setModuleClassLoader(JModuleClassLoader moduleClassLoader) {
        this.moduleClassLoader = moduleClassLoader;
    }

    public void setDefaultAction(JAction defaultAction) {
        this.defaultAction = defaultAction;
    }

    public void setActions(Map<String, JAction> actions) {
        this.actions = actions;
    }

    public void setListeners(List<JModuleListener> listeners) {
        this.listeners = listeners;
    }

    public void setBeanProvider(JBeanProvider beanProvider) {
        this.beanProvider = beanProvider;
    }

    /**
     * 发布模块事件
     * 
     * @param event 模块事件
     */
    protected void publishModuleEvent(JModuleEvent event) {
        if (listeners == null) {
            return;
        }
        for (JModuleListener listener : listeners) {
            try {
                event.publishModuleEvent(listener);
            } catch (Exception e) {
                logger.error("publish module event has error", e);
            }
        }
    }

    /**
     * 发布模块加载事件
     * 
     */
    protected void publishLoadedEvent() {
        this.publishModuleEvent(new JModuleEvent() {
            @Override
            public void publishModuleEvent(JModuleListener listener) {
                listener.onLoaded(JDefaultModule.this);
            }
        });
    }

    /**
     * 发布模块卸载事件
     * 
     */
    protected void publishUnloadedEvent() {
        this.publishModuleEvent(new JModuleEvent() {
            @Override
            public void publishModuleEvent(JModuleListener listener) {
                listener.onUnloaded(moduleConfig);
            }
        });
    }

    /**
     * 发布模块激活事件
     * 
     */
    protected void publishActivedEvent() {
        this.publishModuleEvent(new JModuleEvent() {
            @Override
            public void publishModuleEvent(JModuleListener listener) {
                if (listener instanceof JMultiVersionModuleListener) {
                    ((JMultiVersionModuleListener) listener).onActived(JDefaultModule.this);
                }
            }
        });
    }

    /**
     * 发布模块取消激活事件
     * 
     */
    protected void publishUnActivedEvent() {
        this.publishModuleEvent(new JModuleEvent() {
            @Override
            public void publishModuleEvent(JModuleListener listener) {
                if (listener instanceof JMultiVersionModuleListener) {
                    ((JMultiVersionModuleListener) listener).onUnActived(JDefaultModule.this);
                }
            }
        });
    }

    /**
     * 模块事件
     * 
     * @author jianggujin
     *
     */
    protected static interface JModuleEvent {
        void publishModuleEvent(JModuleListener listener);
    }

    @Override
    public JBeanProvider getBeanProvider() {
        return beanProvider;
    }

    public static enum JLifeState {
        CREATED, INITIALIZED, DESTROYED
    }
}
